/**
 *	The NeuroCoSA Toolkit
 *	Copyright (C) 2003-6 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween(mk2)
 * @license	LGPL
 */
package org.stumeikle.NeuroCoSA;
import java.util.*;
import org.stumeikle.NeuroCoSA.Debug.NeuroCoSADEBUG;
import org.stumeikle.NeuroCoSA.NIS.*;

//complete re-write i think today. 

/**
 * The Brain Class. Forms the basis of the NeuroCoSA system. Contains lobes.
 * 
 * A brain is devired from DPUMachine so can be any network of DPUS. In general however
 * it is a set of lobes with inputs and outputs. 
 * 
 * @author	Stuart Meikle
 * @version	2006-halloween(mk2)
 *
 */
public class	Brain extends DPUMachine //brain takes datablock and returns datablock
{  
    public static final double	undefined_double= -999999.0; /** just an unlikely number */
    BrainInfoService		iBIS;
    InfoLong			iTime;
    NeuroCoSADEBUG		iNeuroCoSADEBUG;
    long			iNextUpdateTimeDelta;/** for debugging */
    long			iNextUpdateTime;/** for debugging */

    //-----------------------------------------------------------------------------------------------
    public Brain()
    {
	iBIS = new BrainInfoService();
	iNeuroCoSADEBUG=null;
	iNextUpdateTime = Long.MAX_VALUE; 
	iNextUpdateTimeDelta = 0;
System.out.println("Time id3 = " + iBIS.findInfoLong("BrainTime").getID() );
    }
    
    //-----------------------------------------------------------------------------------------------
    public BrainInfoService	getInfoService()
    { return iBIS; }

    public void			enableGraphicalDebug()
    { iNeuroCoSADEBUG = new NeuroCoSADEBUG(this); 
      setStopped();}

    //add in: name setting. update , time update, initialisation etc
    public void			getReady()
    {
	//called AFTER the user has created the DPUs and linked them up
	//this routine will reset the clock,
	//order the DPUs
	//store info into the brain info service
	//etc
System.out.println("Time id2 = " + iBIS.findInfoLong("BrainTime").getID() );
	rationalise();
	sortComponents();

	iTime = iBIS.findInfoLong("BrainTime");	iTime.setValue(0);
	iBIS.findInfoLong("NumberOfCortices").setValue(getNumDPUs());
	iBIS.findInfoLong("CortexDepth").setValue(computeDepth());
System.out.println("Time id = " + iBIS.findInfoLong("BrainTime").getID() );
System.out.println("Number of Cortices ID = " + iBIS.findInfoLong("NumberOfCortices").getID() );
System.out.println("Cortex Depth ID = " + iBIS.findInfoLong("CortexDepth").getID() );

	//call getReady for each of the lobes! they need to initialise their
	//info services too
	ListIterator	i = getComponents().listIterator();
	for(;i.hasNext();)
	{
	    DPU d= (DPU) i.next();
	    d.getReady();
	}
    }

    public	DataBlock	update(DataBlock ip)
    {

	if (iNeuroCoSADEBUG != null)
	{
	    while (System.currentTimeMillis() < iNextUpdateTime)
	    {
	    	try{	    	Thread.sleep(50);
		} catch( Exception e ) {}
	    }
	    
	    if (iNextUpdateTimeDelta == Long.MAX_VALUE)
		iNextUpdateTime = Long.MAX_VALUE;
	    else
	        iNextUpdateTime += iNextUpdateTimeDelta;
	}

	//update the time
	iTime.incr();	//updates subscribers too. IS THERE ANY NEED?

	return super.update(ip);
    }

    public 	void		addCortex( Cortex l )
    { super.addDPU( (DPU)l ); 
    }

    public	CortexInfoService findNamedCortexInfoService( String n )
    {
	//return the info service of the named cortex
	Cortex		c;
	ListIterator	i = getComponents().listIterator();
	for(;i.hasNext();)
	{
	    DPU d= (DPU) i.next();
	    
	    try{ c= (Cortex) d; 
		if (c.getName().compareTo(n)==0)
			return c.getInfoService();
	    }catch(Exception e) {}
	}

	return null;
    }

    //called by the ui if there is debug enabled
    public 			void		setFullSpeed()
    {
	iNextUpdateTime = 0;
	iNextUpdateTimeDelta = 0;
    }
    public 			void		setStopped()
    {
	iNextUpdateTime = Long.MAX_VALUE;
	iNextUpdateTimeDelta = 0;
    }
    public			void		setOneStep()
    {
	iNextUpdateTime = System.currentTimeMillis() + 250;
	iNextUpdateTimeDelta = Long.MAX_VALUE;
    }

}


